/*
 * Created on 08.12.2003
 */
package observations;

import java.util.*;

/**
 <code>Measurement</code> Represents something like 'bloodpressure 120
 * mm/Hg'. Measurement is part of Fowler's pattern 'Measurement'. It represents
 * the individual measurement. It is linked to the object being measured (the
 * patient) and to a phenomenon type that describes the kind of measurement
 * being made. It's also part of the pattern 'Observation'.
 
 @author Sascha Hemminger
 @version 1.0 2004-08-10
 @see observations.PhenomenonType
 @see observations.Patient
 @see observations.Observation
 */
public class Measurement extends Observation {

  private Quantity amount;

  private PhenomenonType phenomenonType;

  /**
   * Constructs a Measurement object.
   
   @param amount
   *            measured quantity
   @param phenomenonType
   *            type of the measurement
   @param patient
   *            measured patient
   @param whenObserved
   *            when did you observe the measurement
   @throws OutOfRangeException
   *             if the amount is not valid
   */
  public Measurement(Quantity amount, PhenomenonType phenomenonType,
      Patient patient, Date whenObservedthrows OutOfRangeException {

    if (!phenomenonType.validRangeIncludes(amount))
      throw new OutOfRangeException();
    initialize(patient, whenObserved);
    this.amount = amount;
    this.phenomenonType = phenomenonType;
    checkInvariant();
    phenomenon = calculatePhenomenonFor(amount);

  }

  /**
   * Gives the measured amount.
   
   @return amount of Measurement
   */
  public Quantity amount() {
    return amount;
  }

  /*
   * ConstraintCheck (would have been easier in Eiffel)
   */
  private void assertNonNull(Object arg, String message) {
    if (arg == null)
      throw new NullPointerException(message);
  }

  /**
   * Gives a valuation in quality for a given amount.
   
   @param arg
   *            amount to calculate Phenomenon for
   @return Phenomenon for particular amount
   */
  public Phenomenon calculatePhenomenonFor(Quantity arg) {
    return phenomenonType.getPhenomenonIncluding(arg);
  }

  /*
   * ConstraintCheck (would have been easier in Eiffel)
   */
  private void checkInvariant() {
    assertNonNull(phenomenonType, "Null phenomenon type");
    assertNonNull(amount, "Null amount");
  }

  /**
   * Gives the phenomenon for this measurement.
   
   @return the particular phenomenon
   */
  public Phenomenon getPhenomenon() {
    return phenomenon;
  }
}